
// === uuString ===
// depend: uuMeta
/*
String.prototype.sprintf(var_args, ...) - return string
String.prototype.trim() - return string
String.prototype.trimLef() - return string
String.prototype.trimRight() - return string
uuMeta.sprintf(format, var_args, ...) - return string
 */
(function() {
var _string, // inner namespace
    NUMBER  = 0x0001,
    FLOAT   = 0x0002,
    LITERAL = 0x0004,
    SIGNED  = 0x0010,
    UNSIGNED= 0x0020,
    PREFIX  = 0x0040,
    PRECIS  = 0x0080, // precision
    OCTET   = 0x0100,
    HEX     = 0x0200,
    NOINDEX = 0x0400,
    NOWIDTH = 0x0800,
    TOUPPER = 0x1000,
    TONUM   = 0x2000, // to number
    TOASCII = 0x4000, // to printable
    IGZERO  = 0x8000, // ignore zero flag (eg: "%05d" -> "%5d")
    DECODE  = {
      i: NUMBER | SIGNED | IGZERO,
      d: NUMBER | SIGNED | IGZERO,
      u: NUMBER | UNSIGNED | IGZERO,
      o: NUMBER | UNSIGNED | IGZERO | PREFIX | OCTET,
      x: NUMBER | UNSIGNED | IGZERO | PREFIX | HEX,
      X: NUMBER | UNSIGNED | IGZERO | PREFIX | HEX | TOUPPER,
      f: FLOAT | SIGNED | PRECIS,
      c: TONUM | NOWIDTH,
      A: TOASCII | NOWIDTH,
      s: LITERAL | PRECIS,
      "%": LITERAL | NOINDEX | NOWIDTH
    },
    REX = /%(?:(\d+)\$)?(#|0)?(\d+)?(?:\.(\d+))?(l)?([%iduoxXfcAs])/g,
    N = "number",
    UNSIGNED_NUM = 0x100000000;

_string = {
  sprintf: function(fmt,        // @param String: sprintf format string
                    var_args) { // @param Mix: sprintf args
    var next = 1, idx = 0, av = arguments;

    return fmt.replace(REX, function(m, aidx, flag, width, prec, size, types) {
      var v, w = DECODE[types], fn = String.fromCharCode;

      idx = aidx ? parseInt(aidx) : next++;

      !(w & NOINDEX) && (v = (av[idx] === void 0) ? "undefined" : av[idx]);
      w & NUMBER  && (v = parseInt(v));
      w & FLOAT   && (v = parseFloat(v));
      w & LITERAL && (v = ((types === "s" ? v : types) || "").toString());
      if (w & (NUMBER | FLOAT) && isNaN(v)) { return ""; }

      w & UNSIGNED && (v = (v >= 0) ? v : v % UNSIGNED_NUM + UNSIGNED_NUM);
      w & OCTET   && (v = v.toString(8));
      w & HEX     && (v = v.toString(16));
      w & PREFIX  && (flag === "#") && (v = ((w & OCTET) ? "0" : "0x") + v);
      w & PRECIS  && prec &&
                     (v = (w & FLOAT) ? v.toFixed(prec) : v.substring(0, prec));
      w & TONUM   && (v = (typeof v !== N || v < 0) ? "" : fn(v));
      w & TOASCII && (v = (typeof v !== N || v < 0) ? "" : (v < 32 || v > 126)
                                                    ? "." : fn(v));
      w & IGZERO  && (flag = (flag === "0") ? "" : flag);
      v = w & TOUPPER ? v.toString().toUpperCase() : v.toString();
      if (w & NOWIDTH || width === void 0 || v.length >= width) {
        return v;
      }
      // -- pad zero or space ---
      flag = flag || " ";
      size = width - v.length;

      if (flag === "0" && (w & SIGNED) && v.indexOf("-") !== -1) {
        // "-123" -> "-00123"
        return "-" + Array(size + 1).join("0") + v.substring(1);
      }
      return Array(size + 1).join((flag === "#") ? " " : flag) + v;
    });
  }
};

uuMeta.mix(String.prototype, {
  // String.prototype.sprintf
  sprintf: function(var_args) { // @param Mix: sprintf args
                                // @return String:
    var args = uu.toArray(arguments);
    args.unshift(this);
    return uu.sprintf.apply(this, args);
  },

  // String.prototype.trim - trim both side whitespace
  trim: function() { // @return String:
    return this.replace(/^\s+|\s+$/g, "");
  },

  // String.prototype.trimLeft - trim left side whitespace
  trimLeft: function() { // @return String:
    return this.replace(/^\s+/g, "");
  },

  // String.prototype.trimRight - trim right side whitespace
  trimRight: function() { // @return String:
    return this.replace(/\s+$/g, "");
  }
}, 0, 0);

// --- initialize ---

// --- export ---
uuMeta.mix(uuMeta, _string);

})(); // uuString scope
